package com.zimo.download;

import com.zimo.download.exception.DownloadException;
import com.zimo.download.info.PointerOffset;
import com.zimo.download.info.ServerFileINFO;
import com.zimo.download.thread.ThreadDownload;
import com.zimo.utils.Connection;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


/**
 * 单线程下载类，暂停，获取速度，是否下载完成都没有事件支持，只能通过调用方法来获取方法返回值进行监听下载
 * 暂停，获取速度都只能通过实例来进行（调用startDownload的实例才能获取到）
 * 调用startDownload它又返回值，如果下载完就返回true。
 *
 * =================注意======================
 * |调用startDownload方法前需要给线程设置一个名称 |
 * |名称格式   文件名(唯一) --- 当前线程数       |
 * =========================================
 */
public class SingleThreadDownload extends DownloadImpl{

    //获取logger对象： 传入当前类的class，这样代表这个类输出的日志信息
    private Logger logger = Logger.getLogger(SingleThreadDownload.class);
    //停止下载标志
    private static volatile boolean isStop = false;

    private long speed=0;
    @Override
    public boolean startDownload(URL url, String filePath, PointerOffset pointerOffset) {
        RandomAccessFile raf = null;   //本地文件流
        InputStream in = null;  //网络文件流
        DownloadCacheImpl downloadCache =null;//缓存断点流
        try{
            //创建随机读写文件对象
            raf = new RandomAccessFile(filePath, "rw");
            //当前线程这个位置开始写
            raf.seek(pointerOffset.getSTART());

            logger.info("多线程下载管理器已创建" +
                    "\n>>>URL: "+url+
                    "\n>>>文件名称: "+ServerFileINFO.getFileName(url)+
                    "\n>>>文件大小: "+ServerFileINFO.getFileSize(url)+ " byte"+
                    "\n>>>文件保存地址: "+filePath+
                    "\n>>>下载器: "+this.getClass()+
                    "\n>>>是否强制分块下载: "+true+
                    "\n>>>当前时间: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            //缓存断点流初始化
            downloadCache = new DownloadCacheImpl(url.toString(),filePath,Thread.currentThread().getName());
            //网络输入流
            in =Connection.getInputStream(url);
            //追踪下载进度/断点
            long start =pointerOffset.getSTART();
            long time = System.currentTimeMillis();
            //把数据写到文件中
            int len = -1;
            byte[] buffer = new byte[32*1024];//缓存区,32kb(12mb带宽，1/32最大缓存)
            while(in != null && (len = in.read(buffer))!=-1 ){
                raf.write(buffer, 0, len);//下载网络文件到本地

                //更新进度
                start= start+len;
                speed=speed+len;

                //响应当前线程下载速度监听,单位byte
                if (System.currentTimeMillis() - time >= 1000) {
                    time=System.currentTimeMillis();
                    speed=0;
                }

                //输出断点
                downloadCache.setBreakpoint(start,pointerOffset.getEND(),filePath);

                //停止下载标志成立,停止下载
                if (isStop){
                    synchronized(this.getClass()){
                        logger.debug(filePath+" 下载被暂停");
                        break;
                    }
                }
            }
        }catch (Exception e){
            //抛出线程异常
            try {
                logger.error("单线程下载"+filePath+"文件出现异常,具体原因: ",e);
                throw new DownloadException(Thread.currentThread().getName()+": 线程下载文件出现异常");
            } catch (DownloadException downloadException) {}
            //返回false
            return false;
        }finally {
            speed=0;
            //关闭网络流
            if (in!=null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error(Thread.currentThread().getName()+"线程未能成功关闭"+in);
                }
            }
            //关闭本地流
            if (raf!=null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    logger.error(Thread.currentThread().getName()+"线程未能成功关闭"+raf);
                }
            }
            //关闭断点流
            if (downloadCache != null){
                downloadCache.close();
            }
        }

        //输出日志
        logger.info("开始下载 :"+ pointerOffset.getSTART() +"-"+ pointerOffset.getEND());
        return true;
    }


    /**
     * 续传
     * @param timFilePath  缓存文件路径
     * @return  是否开始下载
     */
    public  boolean continuation(String timFilePath) throws IOException {
        //获取断点类
        DownloadCacheImpl downloadCache = new DownloadCacheImpl(timFilePath);
        //获取断点文件里面的指针集合
        List<PointerOffset> pointerOffsets = downloadCache.getPointerOffsets();
        //从缓存文件里面获取URL
        String url = downloadCache.readURL();
        //从缓存文件里面获取文件保存位置
        String filepath = downloadCache.readPath();

        if (pointerOffsets.size() == 1){
            //设置好，下载地址，文件保存地址，线程指针偏移量，下载实现类
            //这里将保持路径和文件名分离了，在底层他们是不分离的
            Thread thread = new Thread(new ThreadDownload(new URL(url), filepath, pointerOffsets.get(0),new DownloadImpl()));
            thread.setName(ServerFileINFO.getFileName(new URL(url)) +" --- "+0);//设置线程名字
            thread.start();//开始下载
        }else {
            logger.error("断点读取到异常信息 ： "+timFilePath+"非壹个断点，无法进行单线程下载");
            return false;
        }
        return true;
    }


    public boolean stopDownload() {
        isStop=true;
        return true;
    }

    public long getSpeed(){
        return speed;
    }
}
